/*
 * Copyright (c) 2023. Shanghai HEADING information Engineering Co., Ltd. All rights reserved.
 */

package com.lovely602.boot.bootdemo.controller.java;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.lovely602.boot.bootdemo.domain.common.RestResponse;

import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lizhixing
 */
@Api(tags = "synchronized服务")
@RestController
@RequestMapping(value = "/v1/bff/web/synchronized", produces = "application/json;charset=utf-8")
@Slf4j
public class SynchronizedController {

  private List<Integer> data = new ArrayList<>();

  // 不涉及共享资源的慢方法
  private void slow() {
    try {
      TimeUnit.MILLISECONDS.sleep(10);
    } catch (InterruptedException e) {
      log.error("方法执行异常", e);
    }
  }

  @GetMapping("get")
  public RestResponse<Integer> get() {
    return RestResponse.success(data.size());
  }

  @GetMapping("{value}")
  public RestResponse<Void> set(@PathVariable(value = "value") Integer value) {
    data.add(value);
    return RestResponse.success();
  }

  @GetMapping("wrong")
  public int wrong() {
    long begin = System.currentTimeMillis();
    IntStream.rangeClosed(1, 1000).parallel().forEach(i -> {
      // 加锁粒度太粗了
      synchronized (this) {
        slow();
        data.add(i);
      }
    });
    log.info("took: {}", System.currentTimeMillis() - begin);
    return data.size();
  }

  @GetMapping("right")
  public int right() {
    long begin = System.currentTimeMillis();
    IntStream.rangeClosed(1, 1000).parallel().forEach(i -> {
      slow();
      // 只对List加锁
      synchronized (data) {
        data.add(i);
      }
    });
    log.info("took: {}", System.currentTimeMillis() - begin);
    return data.size();
  }

}
